﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Learning_Ruber_Band_selection
{
    class EnhancedPictureBox : PictureBox
    {

        public EnhancedPictureBox()
        {
            this.Paint += new PaintEventHandler(PictureBox1_Paint);
            this.MouseDown += new MouseEventHandler(PictureBox1_MouseDown);
            this.MouseMove += new MouseEventHandler(PictureBox1_MouseMove);
            this.MouseUp += new MouseEventHandler(PictureBox1_MouseUp);

        }

        #region points translations modified from ryshad's post

        private Point ConvertPointToImage(Point clicked)
        {
            if (this.SizeMode == PictureBoxSizeMode.Zoom)
            {
                //get size of original image
                Size size = this.Image.Size;
                //get value of scale
                float num = Math.Min((float)(((float)ClientRectangle.Width) / ((float)size.Width)), (float)(((float)ClientRectangle.Height) / ((float)size.Height)));

                //scale size to calculate translation
                size.Width = (int)(size.Width * num);
                size.Height = (int)(size.Height * num);

                //reverse translation
                clicked.X -= (ClientRectangle.Width - size.Width) / 2;
                clicked.Y -= (ClientRectangle.Height - size.Height) / 2;

                //reverse scale
                clicked.X = (int)(clicked.X / num);
                clicked.Y = (int)(clicked.Y / num);

                //return image coordinates
                return clicked;
            }
            else if (this.SizeMode == PictureBoxSizeMode.CenterImage)
            {
                //how the centering works
                //rectangle.X += (rectangle.Width - this.image.Width) / 2;
                // rectangle.Y += (rectangle.Height - this.image.Height) / 2;
                //--

                // got this online
                // - http://www.codeproject.com/KB/miscctrl/PictureBoxExtended.aspx


                int diffWidth = this.ClientRectangle.Width - Image.Width;
                int diffHeight = this.ClientRectangle.Height - Image.Height;

                diffWidth /= 2;
                diffHeight /= 2;

                clicked.X -= diffWidth;
                clicked.Y -= diffHeight;

                return clicked;

            }
            else if (this.SizeMode == PictureBoxSizeMode.StretchImage)
            {
                // Make sure our control width and height are not 0
                if (Width == 0 || Height == 0) return clicked;
                // First, get the ratio (image to control) the height and width
                float ratioWidth = (float)Image.Width / Width;
                float ratioHeight = (float)Image.Height / Height;
                // Scale the points by our ratio
                float newX = clicked.X;
                float newY = clicked.Y;
                newX *= ratioWidth;
                newY *= ratioHeight;
                return new Point((int)newX, (int)newY);

            }
            else
            {
                return clicked;
            }
        }

        private Rectangle ConvertRectangleToImage(Rectangle clicked)
        {
            if (this.SizeMode != PictureBoxSizeMode.Zoom)
            {
                return clicked;
            }
            //get size of original image
            Size size = this.Image.Size;
            //get value of scale
            float num = Math.Min((float)(((float)ClientRectangle.Width) / ((float)size.Width)), (float)(((float)ClientRectangle.Height) / ((float)size.Height)));

            //scale size to calculate translation
            size.Width = (int)(size.Width * num);
            size.Height = (int)(size.Height * num);

            //reverse translation
            clicked.X -= (ClientRectangle.Width - size.Width) / 2;
            clicked.Y -= (ClientRectangle.Height - size.Height) / 2;

            //reverse scale
            clicked.X = (int)(clicked.X / num);
            clicked.Y = (int)(clicked.Y / num);

            clicked.Width = (int)(clicked.Width / num);
            clicked.Height = (int)(clicked.Height / num);

            //return image coordinates
            return clicked;
        }

        // image coordinates to zoomed methods

        private Point ConvertToZoomed(Point image)
        {
            //get size of original image
            Size size = this.Image.Size;

            //get value of scale
            float num = Math.Min((float)(((float)ClientRectangle.Width) / ((float)size.Width)), (float)(((float)ClientRectangle.Height) / ((float)size.Height)));

            //scale size to calculate translation
            size.Width = (int)(size.Width * num);
            size.Height = (int)(size.Height * num);

            //apply scale to Point
            image.X = (int)(image.X * num);
            image.Y = (int)(image.Y * num);

            //apply translation to Point
            image.X += (ClientRectangle.Width - size.Width) / 2;
            image.Y += (ClientRectangle.Height - size.Height) / 2;

            //return Zoomed Point
            return image;

        }

        private Rectangle ConvertToZoomed(Rectangle selection)
        {
            //get size of original image
            Size size = this.Image.Size;

            //get value of scale
            float num = Math.Min((float)(((float)ClientRectangle.Width) / ((float)size.Width)), (float)(((float)ClientRectangle.Height) / ((float)size.Height)));

            //scale size to calculate translation
            size.Width = (int)(size.Width * num);
            size.Height = (int)(size.Height * num);

            //apply scale to Selection
            selection.X = (int)(selection.X * num);
            selection.Y = (int)(selection.Y * num);
            selection.Width = (int)(selection.Width * num);
            selection.Height = (int)(selection.Height * num);

            //apply translation to Selection
            selection.X += (ClientRectangle.Width - size.Width) / 2;
            selection.Y += (ClientRectangle.Height - size.Height) / 2;

            //return Zoomed Selection
            return selection;

        }

        #endregion


        Rectangle selection;
        bool m_Drawing = false;
        Point m_Start;
        bool m_mover = false;
        Size m_mover_size;
        Point m_distance;
        bool m_H_sizer = false;
        bool m_V_sizer = false;
        Point m_droploc;
        bool m_HT_sizer = false;
        bool m_VT_sizer = false;

        bool m_NE_sizer = false;
        bool m_SW_sizer = false;
        bool m_NW_sizer = false;


        bool OverImage = false;


        private void PictureBox1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right && selection.Contains(e.Location))
            {


                if (SizeMode == PictureBoxSizeMode.CenterImage)
                {

                    Point start = ConvertPointToImage(selection.Location);

                    Rectangle sect = new Rectangle(start, selection.Size);

                    Bitmap b2 = ((Bitmap)Image).Clone(sect, Image.PixelFormat);

                    Clipboard.SetImage((Image)b2);
                }
                else if (SizeMode == PictureBoxSizeMode.Normal)
                {
                    Bitmap b2 = ((Bitmap)Image).Clone(selection, Image.PixelFormat);
                    Clipboard.SetImage((Image)b2);
                }
                else if (SizeMode == PictureBoxSizeMode.Zoom)
                {
                    Rectangle sect = ConvertRectangleToImage(selection);


                    Bitmap b2 = ((Bitmap)Image).Clone(sect, Image.PixelFormat);

                    Clipboard.SetImage((Image)b2);

                    this.Invalidate();

                    // MessageBox.Show(e.Location.ToString() + " clientw=" + ClientRectangle.Height.ToString() + "imageh=" + Image.Height.ToString() + " image w=" + Image.Width.ToString() + "endrect=" + (selection.X + selection.Width).ToString());

                }

                MessageBox.Show("Copied to clip board");

                return;

            }


            Rectangle mini = new Rectangle(selection.Location.X + 4, selection.Location.Y + 4, selection.Width - 8, selection.Height - 8);
            Rectangle selectionM = new Rectangle(selection.Location.X - 3, selection.Location.Y - 3, selection.Width + 6, selection.Height + 6);
            Rectangle SEsizeRect = new Rectangle(selection.Location.X + selection.Width - 3, selection.Location.Y + selection.Height - 3, 6, 6);
            Rectangle NEsizeRect = new Rectangle(selection.Location.X + selection.Width - 3, selection.Location.Y - 3, 6, 6);
            Rectangle SWsizeRect = new Rectangle(selection.Location.X - 3, selection.Location.Y + selection.Height - 3, 6, 6);
            Rectangle NWsizeRect = new Rectangle(selection.Location.X - 3, selection.Location.Y - 3, 6, 6);
            if (mini.Contains(e.Location))
            {
                m_mover = true;
                m_distance = new Point(e.Location.X - selection.Location.X, e.Location.Y - selection.Location.Y);
                m_mover_size = new Size(selection.Width, selection.Height);
            }
            else if (SEsizeRect.Contains(e.Location))
            {
                m_Drawing = true;
                return;
            }
            else if (NEsizeRect.Contains(e.Location))
            {
                m_distance = new Point(e.Location.X - selection.Location.X, e.Location.Y - selection.Location.Y);
                m_NE_sizer = true;
                return;
            }
            else if (SWsizeRect.Contains(e.Location))
            {
                m_distance = new Point(e.Location.X - selection.Location.X, e.Location.Y - selection.Location.Y);
                m_SW_sizer = true;
                return;
            }
            else if (NWsizeRect.Contains(e.Location))
            {
                m_distance = new Point(e.Location.X - selection.Location.X, e.Location.Y - selection.Location.Y);
                m_NW_sizer = true;
                return;
            }
            else if (selectionM.Contains(e.Location) && e.Location.X > (mini.Location.X + mini.Width))
            {
                m_H_sizer = true;
            }
            else if (selectionM.Contains(e.Location) && e.Location.Y > (mini.Location.Y + mini.Height))
            {
                m_V_sizer = true;
            }
            else if (selectionM.Contains(e.Location) && e.Location.X < mini.Location.X)
            {
                m_distance = new Point(e.Location.X - selection.Location.X, e.Location.Y - selection.Location.Y);
                m_HT_sizer = true;
            }
            else if (selectionM.Contains(e.Location) && e.Location.Y < mini.Location.Y)
            {
                m_distance = new Point(e.Location.X - selection.Location.X, e.Location.Y - selection.Location.Y);
                m_VT_sizer = true;
            }
            else
            {
                //Remember where mouse was pressed
                m_Start = e.Location;
                //Clear the selection rectangle
                selection = new Rectangle(); ;
                this.Invalidate();
                //Selection drawing is on
                m_Drawing = true;
            }
        }

        private void // ERROR: Handles clauses are not supported in C#
        PictureBox1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (m_Drawing)
            {

                if (SizeMode == PictureBoxSizeMode.Normal)
                {
                    Point newDrop = e.Location;
                    Point p = e.Location;
                    if (p.X < 0)
                    {
                        newDrop.X = 0;
                    }
                    if (p.X > Image.Width)
                    {
                        newDrop.X = Image.Width;
                    }
                    if (p.Y < 0)
                    {
                        newDrop.Y = 0;
                    }
                    if (p.Y > Image.Height)
                    {
                        newDrop.Y = Image.Height;
                    }

                    selection = RectangleFromPoints(m_Start, newDrop);
                    //save the intermediate point
                    m_droploc = newDrop;
                    //Update selection
                }

                else if (this.SizeMode == PictureBoxSizeMode.Zoom)
                {
                    Point newDrop = e.Location;

                    Point p = ConvertPointToImage(e.Location);
                    if (p.X < 0)
                    {
                        newDrop.X = ConvertToZoomed(new Point(0, ConvertPointToImage(e.Location).Y)).X;
                    }
                    if (p.X > Image.Width)
                    {
                        newDrop.X = ConvertToZoomed(new Point(Image.Width, ConvertPointToImage(e.Location).Y)).X;
                    }
                    if (p.Y < 0)
                    {
                        newDrop.Y = ConvertToZoomed(new Point(ConvertPointToImage(e.Location).X, 0)).Y;
                    }
                    if (p.Y > Image.Height)
                    {
                        newDrop.Y = ConvertToZoomed(new Point(ConvertPointToImage(e.Location).X, Image.Height)).Y;
                    }

                    selection = RectangleFromPoints(m_Start, newDrop);
                    //save the intermediate point
                    m_droploc = newDrop;
                    //Update selection

                }
                else
                {
                    selection = RectangleFromPoints(m_Start, e.Location);
                    m_droploc = e.Location;
                }


                this.Invalidate();
            }
            else if (m_mover)
            {
                if (this.SizeMode == PictureBoxSizeMode.Normal)
                {
                    selection = new Rectangle(e.Location.X - m_distance.X, e.Location.Y - m_distance.Y, m_mover_size.Width, m_mover_size.Height);
                    //save the start point
                    m_Start = selection.Location;
                    //save the intermediate point
                    m_droploc = new Point(selection.Location.X + selection.Width, selection.Location.Y + selection.Height);
                    //Update selection
                }
                else if (this.SizeMode == PictureBoxSizeMode.Zoom)
                {
                    Point rectloc = e.Location;

                    if ((e.Location.X - m_distance.X) < ConvertToZoomed(new Point(0, 0)).X)
                    {
                        rectloc.X = ConvertToZoomed(new Point(0, 0)).X;
                    }
                    else if (((e.Location.X - m_distance.X) + m_mover_size.Width) >= ConvertToZoomed(new Point(Image.Width, 0)).X)
                    {
                        int rectWidth = m_mover_size.Width;

                        float num = Math.Min((float)(((float)this.ClientRectangle.Width) / ((float)Image.Width)), (float)(((float)this.ClientRectangle.Height) / ((float)Image.Height)));
                        rectWidth = (int)((rectWidth + 1) / num);
                        //rectHeight = (int)(rect.Height / num);
                        rectloc.X = ConvertToZoomed(new Point(Image.Width - rectWidth, 0)).X;
                    }
                    else
                    {
                        rectloc.X = e.Location.X - m_distance.X;

                    }

                    if ((e.Location.Y - m_distance.Y) < ConvertToZoomed(new Point(0, 0)).Y)
                    {
                        rectloc.Y = ConvertToZoomed(new Point(0, 0)).Y;
                    }
                    else if (((e.Location.Y - m_distance.Y) + m_mover_size.Height) >= ConvertToZoomed(new Point(0, Image.Height)).Y)
                    {
                        int rectHeight = m_mover_size.Height;

                        float num = Math.Min((float)(((float)this.ClientRectangle.Width) / ((float)Image.Width)), (float)(((float)this.ClientRectangle.Height) / ((float)Image.Height)));
                        //rectWidth = (int)((rectWidth + 1) / num);
                        rectHeight = (int)((rectHeight + 1) / num);
                        rectloc.Y = ConvertToZoomed(new Point(0, Image.Height - rectHeight)).Y;
                    }
                    else
                    {
                        rectloc.Y = e.Location.Y - m_distance.X;

                    }

                    selection = new Rectangle(rectloc.X, rectloc.Y, m_mover_size.Width, m_mover_size.Height);
                    //save the start point
                    m_Start = selection.Location;
                    //save the intermediate point
                    m_droploc = new Point(selection.Location.X + selection.Width, selection.Location.Y + selection.Height);
                    //Update selection

                    //m_distance = new Point(e.Location.X - selection.Location.X, e.Location.Y - selection.Location.Y);

                }

                this.Invalidate();
            }
            else if (m_NE_sizer)
            {
                selection.Width = e.Location.X - selection.Location.X;
                int Ysize = m_droploc.Y - (e.Location.Y + m_distance.Y);
                selection.Location = new Point(m_Start.X, e.Location.Y + m_distance.Y);
                selection.Height = Ysize;
                //save the intermediate point
                m_droploc = new Point(selection.Location.X + selection.Width, selection.Location.Y + selection.Height);
                //Update selection
                this.Invalidate();
                return;
            }
            else if (m_SW_sizer)
            {
                int Xsize = m_droploc.X - (e.Location.X + m_distance.X);
                selection.Location = new Point(e.Location.X + m_distance.X, m_Start.Y);
                selection.Width = Xsize;

                selection.Height = e.Location.Y - selection.Location.Y;


                //Update selection
                this.Invalidate();
                return;
            }
            else if (m_NW_sizer)
            {
                int Xsize = m_droploc.X - (e.Location.X + m_distance.X);
                int Ysize = m_droploc.Y - (e.Location.Y + m_distance.Y);
                selection.Location = new Point(e.Location.X + m_distance.X, e.Location.Y + m_distance.Y);
                selection.Width = Xsize;

                selection.Height = Ysize;

                //Update selection
                this.Invalidate();
                return;
            }
            else if (m_H_sizer)
            {
                selection.Width = e.Location.X - selection.Location.X;
                //save the intermediate point
                m_droploc = new Point(selection.Location.X + selection.Width, selection.Location.Y + selection.Height);
                //Update selection
                this.Invalidate();
            }
            else if (m_V_sizer)
            {
                selection.Height = e.Location.Y - selection.Location.Y;
                //save the intermediate point
                m_droploc = new Point(selection.Location.X + selection.Width, selection.Location.Y + selection.Height);
                //Update selection
                this.Invalidate();
            }
            else if (m_HT_sizer)
            {
                int Xsize = m_droploc.X - (e.Location.X + m_distance.X);
                selection.Location = new Point(e.Location.X + m_distance.X, m_Start.Y);
                selection.Width = Xsize;
                //Update selection
                this.Invalidate();
            }
            else if (m_VT_sizer)
            {
                int Ysize = m_droploc.Y - (e.Location.Y + m_distance.Y);
                selection.Location = new Point(m_Start.X, e.Location.Y + m_distance.Y);
                selection.Height = Ysize;
                //Update selection
                this.Invalidate();
            }

            //show mouse effects
            if (!m_mover && !m_H_sizer && !m_V_sizer && !m_HT_sizer && !m_VT_sizer && !m_Drawing)
            {
                Rectangle mini = new Rectangle(selection.Location.X + 4, selection.Location.Y + 4, selection.Width - 8, selection.Height - 8);
                Rectangle SEsizeRect = new Rectangle(selection.Location.X + selection.Width - 3, selection.Location.Y + selection.Height - 3, 6, 6);
                Rectangle selectionM = new Rectangle(selection.Location.X - 3, selection.Location.Y - 3, selection.Width + 6, selection.Height + 6);
                Rectangle NEsizeRect = new Rectangle(selection.Location.X + selection.Width - 3, selection.Location.Y - 3, 6, 6);
                Rectangle SWsizeRect = new Rectangle(selection.Location.X - 3, selection.Location.Y + selection.Height - 3, 6, 6);
                Rectangle NWsizeRect = new Rectangle(selection.Location.X - 3, selection.Location.Y - 3, 6, 6);
                if (mini.Contains(e.Location))
                {
                    this.Cursor = Cursors.SizeAll;
                }
                else if (SEsizeRect.Contains(e.Location))
                {
                    this.Cursor = Cursors.SizeNWSE;
                    return;
                }
                else if (NEsizeRect.Contains(e.Location))
                {
                    this.Cursor = Cursors.SizeNESW;
                    return;
                }
                else if (SWsizeRect.Contains(e.Location))
                {
                    this.Cursor = Cursors.SizeNESW;
                    return;
                }
                else if (NWsizeRect.Contains(e.Location))
                {
                    this.Cursor = Cursors.SizeNWSE;
                    return;
                }
                else if (selectionM.Contains(e.Location) && e.Location.X > (mini.Location.X + mini.Width))
                {
                    this.Cursor = Cursors.SizeWE;
                }
                else if (selectionM.Contains(e.Location) && e.Location.Y > (mini.Location.Y + mini.Height))
                {
                    this.Cursor = Cursors.SizeNS;
                }
                else if (selectionM.Contains(e.Location) && e.Location.X < mini.Location.X)
                {
                    this.Cursor = Cursors.SizeWE;
                }
                else if (selectionM.Contains(e.Location) && e.Location.Y < mini.Location.Y)
                {
                    this.Cursor = Cursors.SizeNS;
                }
                else
                {
                    this.Cursor = Cursors.Default;
                }
            }
        }

        //Returns a rectangle from 2 points
        private Rectangle RectangleFromPoints(Point p1, Point p2)
        {
            int x;
            int y;

            if (p1.X <= p2.X)
            {
                x = p1.X;
            }
            else
            {
                x = p2.X;
            }

            if (p1.Y <= p2.Y)
            {
                y = p1.Y;
            }
            else
            {
                y = p2.Y;
            }

            return new Rectangle(x, y, Math.Abs(p1.X - p2.X), Math.Abs(p1.Y - p2.Y));
        }

        private void // ERROR: Handles clauses are not supported in C#
        PictureBox1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            m_Drawing = false;
            m_mover = false;
            m_H_sizer = false;
            m_V_sizer = false;
            m_HT_sizer = false;
            m_VT_sizer = false;
            m_NE_sizer = false;
            m_SW_sizer = false;
            m_NW_sizer = false;

            //save the start point
            m_Start = selection.Location;
            //save the intermediate point
            m_droploc = new Point(selection.Location.X + selection.Width, selection.Location.Y + selection.Height);


        }


        SolidBrush hbr = new SolidBrush(Color.FromArgb(25, Color.Blue));
        Pen borderpen = new Pen(new SolidBrush(Color.FromArgb(100, Color.Blue)));

        private void
        PictureBox1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
        {
            if (selection != null)
            {
                //There is a selection rectangle so draw it
                e.Graphics.FillRectangle(hbr, selection);
                borderpen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
                e.Graphics.DrawRectangle(borderpen, selection);
            }
        }

        private void SelectAll() //NOT FINISHED
        {
            // Rectangle rectangle = LayoutUtils.DeflateRect(base.ClientRectangle, base.Padding);
            Rectangle rectangle = new Rectangle();
            if (this.Image != null)
            {
                switch (SizeMode)
                {
                    case PictureBoxSizeMode.Normal:
                    case PictureBoxSizeMode.AutoSize:
                        rectangle.Size = this.Image.Size;
                        selection = rectangle;
                        return;

                    case PictureBoxSizeMode.StretchImage:
                        selection = rectangle;
                        return;


                    case PictureBoxSizeMode.CenterImage:
                        rectangle.X += (rectangle.Width - this.Image.Width) / 2;
                        rectangle.Y += (rectangle.Height - this.Image.Height) / 2;
                        rectangle.Size = this.Image.Size;
                        selection = rectangle;
                        return;

                    case PictureBoxSizeMode.Zoom:
                        {
                            Size size = this.Image.Size;
                            float num = Math.Min((float)(((float)base.ClientRectangle.Width) / ((float)size.Width)), (float)(((float)base.ClientRectangle.Height) / ((float)size.Height)));
                            rectangle.Width = (int)(size.Width * num);
                            rectangle.Height = (int)(size.Height * num);
                            rectangle.X = (base.ClientRectangle.Width - rectangle.Width) / 2;
                            rectangle.Y = (base.ClientRectangle.Height - rectangle.Height) / 2;
                            selection = rectangle;
                            return;
                        }
                }
            }
        }



    }
}